`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/26 13:59:31
// Design Name: 
// Module Name: rv_csr
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

`include "counter_config.v"
`include "rv_config.v"

module rv_csr(
    input CLK,input RST,
    //Decode-->CSR
    input [4:0] INST_TYPE,
    input [2:0] FUNC3,
    input [4:0] RS1_INDEX,
    input [4:0] RD_INDEX,

    //Decode-->EX Data
    input [31:0] IMM32,
    
    //EX --> CSR
    input [31:0] RS1_FORWARD,

    //CSR controller --> ALL CSR modules
    output [11:0] CSR_ADDR,

    //CSR controller-->CSR_CYCLE
    output CSR_CYCLE_CS,
    //CSR_CYCLE --> CSR controller
    input  [31:0] CSR_CYCLE_DOUT,

    //CSR controller-->CSR_SIG
    output CSR_SIG_CS,
    //CSR_SIG --> CSR controller
    input  [31:0] CSR_SIG_DOUT,

    //CSR controller-->CSR_WAIT_PARA
    output CSR_WAIT_PARA_CS,
    //CSR_WAIT_PARA --> CSR controller
    input  [31:0] CSR_WAIT_PARA_DOUT, 

    //CSR controller-->RV_FLAG
    output CSR_RV_FLAG_CS,

    input [31:0] CSR_THREAD_ID_DOUT,
    
    //CSR -->EX
    output reg [31:0] CSR_DOUT
    );
    wire [11:0] csr_addr=IMM32[11:0];
    assign CSR_ADDR=IMM32[11:0];

    wire csr_cycle_cs;
    assign csr_cycle_cs=((INST_TYPE==`INST_SYSTEM)&
        (FUNC3==`CSRRS)&(RS1_INDEX==5'b0)&
        ((csr_addr==`CSR_CYCLE)|(csr_addr==`CSR_CYCLEH)))?1'b1:1'b0;
    assign CSR_CYCLE_CS=csr_cycle_cs;

    wire csr_sig_cs;
    assign csr_sig_cs=((INST_TYPE==`INST_SYSTEM)&
        (csr_addr==`CSR_THREAD_SIG))?1'b1:1'b0;
    assign CSR_SIG_CS=csr_sig_cs;

    wire csr_wait_para_cs;
    assign  csr_wait_para_cs=((INST_TYPE==`INST_SYSTEM)&
    (csr_addr==`CSR_THREAD_WAIT_PARA))?1'b1:1'b0;
    assign CSR_WAIT_PARA_CS=csr_wait_para_cs;

    wire csr_thread_id_cs;
    assign csr_thread_id_cs=((INST_TYPE==`INST_SYSTEM)&
    (csr_addr==`CSR_THREAD_ID))?1'b1:1'b0;
    
    wire csr_rv_flag_cs;
    assign csr_rv_flag_cs=((INST_TYPE==`INST_SYSTEM)&
    (csr_addr==`CSR_RV_FLAG))?1'b1:1'b0;
    assign CSR_RV_FLAG_CS=csr_rv_flag_cs;

    always @(*) begin
        if(csr_cycle_cs==1'b1) CSR_DOUT=CSR_CYCLE_DOUT;
        else if(csr_sig_cs==1'b1) CSR_DOUT=CSR_SIG_DOUT;
        else if(csr_wait_para_cs==1'b1) CSR_DOUT=CSR_WAIT_PARA_DOUT;
        else if(csr_thread_id_cs==1'b1) CSR_DOUT=CSR_THREAD_ID_DOUT;
        else CSR_DOUT=32'b0;
    end

endmodule

module csr_cycle(
    input CLK,input RST,
    //CSR controller --> ALL CSR modules
    input [11:0] CSR_ADDR,
    //CSR controller-->CSR_CYCLE
    input CSR_CYCLE_CS,
    //CSR_CYCLE --> CSR controller
    output reg [31:0] CSR_CYCLE_DOUT
);
    wire [63:0] counter_dout;
    counter_load_w #(.width(64)) CYCLE_COUNTER(
        CLK,RST,`COUNTER_CMD_INC,64'b0,counter_dout);
    always @(*) begin
        if(CSR_CYCLE_CS==1'b0) CSR_CYCLE_DOUT=32'b0;
        else if(CSR_ADDR==`CSR_CYCLE) CSR_CYCLE_DOUT=counter_dout[31:0];
        else if(CSR_ADDR==`CSR_CYCLEH) CSR_CYCLE_DOUT=counter_dout[63:32];
        else CSR_CYCLE_DOUT=32'b0;
    end
endmodule

module csr_thread_id(
    input [1:0] THREAD_ID,
    output [31:0] CSR_THREAD_ID_DOUT
);
    assign CSR_THREAD_ID_DOUT={30'b0,THREAD_ID};
endmodule

module csr_rv_flag(
    input CLK,input RST,
    //Decode-->CSR
    input [2:0] FUNC3,
    input [4:0] RS1_INDEX,
    //Decode-->EX Data
    input [31:0] IMM32,
    //EX --> CSR
    input [31:0] RS1_FORWARD,
    //CSR controller-->CSR_RV_FLAG
    input CSR_RV_FLAG_CS,

    //csr_rv_flag -->rv_all
    output [31:0] RV_FLAG
);
    wire rv_flag_en;
    wire [31:0] rv_flag_din,cur_rv_flag;
    csr_reg_wr_en RV_FLAG_EN(CSR_RV_FLAG_CS,
        FUNC3,RS1_INDEX,rv_flag_en);
    csr_next_value RV_FLAG_NEXT_VALUE(
        cur_rv_flag,
        FUNC3,
        RS1_FORWARD,
        IMM32,
        rv_flag_din
    );
    regw #(.WIDTH(32)) RV_FLAG_REG(CLK,RST,rv_flag_en,rv_flag_din,cur_rv_flag);
    assign RV_FLAG=cur_rv_flag;

endmodule

//According to Table 9.1
module csr_reg_wr_en(
    input CS,
    input [2:0] FUNC3,
    input [4:0] RS1_INDEX,
    output csr_reg_wr
);
    reg csr_reg_wr0;
    always @(*) begin
        case(FUNC3)
            `CSRRW,`CSRRWI: csr_reg_wr0=1'b1;
            `CSRRS,`CSRRC,`CSRRSI,`CSRRCI:
                if(RS1_INDEX==5'b00000) csr_reg_wr0=1'b0;
                else csr_reg_wr0=1'b1;
            default:csr_reg_wr0=1'b0;
        endcase
    end
    assign csr_reg_wr=csr_reg_wr0&CS;

endmodule
module csr_next_value(
    input [31:0] cur_value,
    input [2:0] FUNC3,
    input [31:0] RS1,
    input [31:0] IMM32,
    output reg [31:0] next_value
);
    always @(*) begin
        case(FUNC3)
            `CSRRW: next_value=RS1;
            `CSRRS: next_value=cur_value|RS1;
            `CSRRC: next_value=cur_value&(~RS1);
            `CSRRWI:next_value=IMM32;
            `CSRRSI:next_value=cur_value|IMM32;
            `CSRRCI:next_value=cur_value&(~IMM32);
            default:next_value=32'h0;
        endcase
    end
endmodule